//+------------------------------------------------------------------+
//|                                                  WaveAnalysis.mqh |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property link      ""
#property version   "1.00"
#property strict

// 波浪类型枚举
enum ENUM_WAVE_TYPE {
    WAVE_IMPULSE,    // 推动浪
    WAVE_CORRECTIVE  // 调整浪
};

// 波浪结构
struct Wave {
    ENUM_WAVE_TYPE type;      // 波浪类型
    int startBar;             // 起始K线
    int endBar;               // 结束K线
    double startPrice;        // 起始价格
    double endPrice;          // 结束价格
    double amplitude;         // 波动幅度
    double duration;          // 持续时间
    bool isComplete;          // 是否完成
};

// Wave structure parameters
struct WavePoint {
    datetime time;
    double price;
    int type;  // 1-5 for impulse waves, A-C for corrective waves
};

// Add new structures for multi-timeframe analysis
struct WaveDivergence {
    bool exists;
    int type;  // 1: bullish, -1: bearish
    datetime startTime;
    datetime endTime;
};

// Wave analysis class
class CWaveAnalysis {
private:
    Wave m_waves[];           // 波浪数组
    int m_waveCount;          // 波浪计数
    int m_currentWave;        // 当前波浪索引
    
    // 波浪识别参数
    double m_minAmplitude;    // 最小波动幅度
    int m_minDuration;        // 最小持续时间
    double m_retracementLevel;// 回调水平
    
    WavePoint m_wavePoints[];
    ENUM_TIMEFRAMES m_timeframes[3];  // Multiple timeframes for confirmation
    WaveDivergence m_divergence;
    double m_waveAccuracy;
    int m_waveConfirmationCount;
    
public:
    // Constructor
    CWaveAnalysis() {
        m_waveCount = 0;
        m_currentWave = -1;
        m_minAmplitude = 0.0001;  // 默认最小波动幅度
        m_minDuration = 5;        // 默认最小持续时间（K线数）
        m_retracementLevel = 0.618; // 默认回调水平
        m_waveAccuracy = 0;
        m_waveConfirmationCount = 0;
        
        // Initialize timeframes (current, higher, lower)
        m_timeframes[0] = PERIOD_CURRENT;
        m_timeframes[1] = GetHigherTimeframe(PERIOD_CURRENT);
        m_timeframes[2] = GetLowerTimeframe(PERIOD_CURRENT);
    }
    
    // Initialize wave analysis
    bool Initialize(double minAmplitude = 0.0001, int minDuration = 5, double retracementLevel = 0.618) {
        m_minAmplitude = minAmplitude;
        m_minDuration = minDuration;
        m_retracementLevel = retracementLevel;
        return true;
    }
    
    // Analyze price data
    bool AnalyzePriceData(const double &high[], const double &low[], const double &close[], int count) {
        if(count < m_minDuration * 2) return false;
        
        // Reset waves array
        ArrayResize(m_waves, 0);
        m_waveCount = 0;
        m_currentWave = -1;
        
        // Find potential waves
        for(int idx = m_minDuration; idx < count - m_minDuration; idx++) {
            // Check if a new wave is forming
            if(IsPotentialWave(high, low, close, idx)) {
                AddWave(high, low, close, idx);
            }
        }
        
        return m_waveCount > 0;
    }
    
    // Check if a bar is a local extreme
    bool IsLocalExtreme(int bar) {
        double currentHigh = iHigh(Symbol(), PERIOD_CURRENT, bar);
        double currentLow = iLow(Symbol(), PERIOD_CURRENT, bar);
        
        // Check for local high
        bool isHigh = true;
        for(int idx = 1; idx <= 2; idx++) {
            if(iHigh(Symbol(), PERIOD_CURRENT, bar-idx) > currentHigh ||
               iHigh(Symbol(), PERIOD_CURRENT, bar+idx) > currentHigh) {
                isHigh = false;
                break;
            }
        }
        
        // Check for local low
        bool isLow = true;
        for(int idx = 1; idx <= 2; idx++) {
            if(iLow(Symbol(), PERIOD_CURRENT, bar-idx) < currentLow ||
               iLow(Symbol(), PERIOD_CURRENT, bar+idx) < currentLow) {
                isLow = false;
                break;
            }
        }
        
        return isHigh || isLow;
    }
    
    // Check if a bar is a potential wave
    bool IsPotentialWave(const double &high[], const double &low[], const double &close[], int barIndex) {
        // Calculate current bar's amplitude
        double currentAmplitude = high[barIndex] - low[barIndex];
        
        // Check if it meets the minimum amplitude requirement
        if(currentAmplitude < m_minAmplitude) return false;
        
        // Check if it meets the minimum duration requirement
        if(barIndex < m_minDuration) return false;
        
        // Check if it's an impulse wave
        if(IsImpulseWave(high, low, close, barIndex)) return true;
        
        // Check if it's a corrective wave
        if(IsCorrectiveWave(high, low, close, barIndex)) return true;
        
        return false;
    }
    
    // Check if a bar is an impulse wave
    bool IsImpulseWave(const double &high[], const double &low[], const double &close[], int barIndex) {
        // Check if the price movement matches an impulse wave pattern
        bool isUpTrend = true;
        bool isDownTrend = true;
        
        // Check for upward trend
        for(int idx = barIndex - m_minDuration; idx < barIndex; idx++) {
            if(close[idx] >= close[idx + 1]) {
                isUpTrend = false;
                break;
            }
        }
        
        // Check for downward trend
        for(int idx = barIndex - m_minDuration; idx < barIndex; idx++) {
            if(close[idx] <= close[idx + 1]) {
                isDownTrend = false;
                break;
            }
        }
        
        return isUpTrend || isDownTrend;
    }
    
    // Check if a bar is a corrective wave
    bool IsCorrectiveWave(const double &high[], const double &low[], const double &close[], int barIndex) {
        // Check if the price movement matches a corrective wave pattern
        double maxPrice = high[barIndex];
        double minPrice = low[barIndex];
        
        // Calculate retracement amplitude
        for(int idx = barIndex - m_minDuration; idx < barIndex; idx++) {
            maxPrice = MathMax(maxPrice, high[idx]);
            minPrice = MathMin(minPrice, low[idx]);
        }
        
        double retracement = (maxPrice - minPrice) * m_retracementLevel;
        
        // Check if it meets the retracement level
        return (high[barIndex] - low[barIndex]) >= retracement;
    }
    
    // Add a new wave
    void AddWave(const double &high[], const double &low[], const double &close[], int barIndex) {
        Wave wave;
        wave.startBar = barIndex - m_minDuration;
        wave.endBar = barIndex;
        wave.startPrice = close[wave.startBar];
        wave.endPrice = close[wave.endBar];
        wave.amplitude = MathAbs(wave.endPrice - wave.startPrice);
        wave.duration = wave.endBar - wave.startBar;
        wave.isComplete = true;
        
        // Determine wave type
        if(IsImpulseWave(high, low, close, barIndex)) {
            wave.type = WAVE_IMPULSE;
        } else {
            wave.type = WAVE_CORRECTIVE;
        }
        
        // Add to waves array
        ArrayResize(m_waves, m_waveCount + 1);
        m_waves[m_waveCount++] = wave;
        m_currentWave = m_waveCount - 1;
    }
    
    // Get current wave
    bool GetCurrentWave(Wave &wave) {
        if(m_currentWave < 0 || m_currentWave >= m_waveCount) return false;
        
        wave = m_waves[m_currentWave];
        return true;
    }
    
    // Get wave count
    int GetWaveCount() {
        return m_waveCount;
    }
    
    // Get wave by index
    bool GetWave(int index, Wave &wave) {
        if(index < 0 || index >= m_waveCount) return false;
        
        wave = m_waves[index];
        return true;
    }
    
    // Predict next wave
    bool PredictNextWave(Wave &predictedWave) {
        if(m_currentWave < 0) return false;
        
        Wave currentWave = m_waves[m_currentWave];
        
        // Predict next wave based on current wave
        predictedWave = currentWave;
        predictedWave.startBar = currentWave.endBar;
        predictedWave.startPrice = currentWave.endPrice;
        
        // Predict based on wave type
        if(currentWave.type == WAVE_IMPULSE) {
            // Impulse wave usually followed by corrective wave
            predictedWave.type = WAVE_CORRECTIVE;
            predictedWave.amplitude = currentWave.amplitude * m_retracementLevel;
        } else {
            // Corrective wave usually followed by impulse wave
            predictedWave.type = WAVE_IMPULSE;
            predictedWave.amplitude = currentWave.amplitude * (1.0 + m_retracementLevel);
        }
        
        predictedWave.isComplete = false;
        return true;
    }
    
    // Update wave prediction
    bool UpdateWavePrediction(const double &high[], const double &low[], const double &close[], int barIndex) {
        if(m_currentWave < 0) return false;
        
        Wave currentWave = m_waves[m_currentWave];
        
        // Check if prediction is accurate
        double currentAmplitude = MathAbs(close[barIndex] - currentWave.startPrice);
        
        if(currentAmplitude >= currentWave.amplitude * 0.8) {
            // Predicted wave is accurate, update wave
            currentWave.endBar = barIndex;
            currentWave.endPrice = close[barIndex];
            currentWave.amplitude = currentAmplitude;
            currentWave.isComplete = true;
            
            m_waves[m_currentWave] = currentWave;
            return true;
        }
        
        return false;
    }
    
    // Get higher timeframe
    ENUM_TIMEFRAMES GetHigherTimeframe(ENUM_TIMEFRAMES timeframe) {
        switch(timeframe) {
            case PERIOD_M1: return PERIOD_M5;
            case PERIOD_M5: return PERIOD_M15;
            case PERIOD_M15: return PERIOD_M30;
            case PERIOD_M30: return PERIOD_H1;
            case PERIOD_H1: return PERIOD_H4;
            case PERIOD_H4: return PERIOD_D1;
            case PERIOD_D1: return PERIOD_W1;
            default: return timeframe;
        }
    }
    
    // Get lower timeframe
    ENUM_TIMEFRAMES GetLowerTimeframe(ENUM_TIMEFRAMES timeframe) {
        switch(timeframe) {
            case PERIOD_W1: return PERIOD_D1;
            case PERIOD_D1: return PERIOD_H4;
            case PERIOD_H4: return PERIOD_H1;
            case PERIOD_H1: return PERIOD_M30;
            case PERIOD_M30: return PERIOD_M15;
            case PERIOD_M15: return PERIOD_M5;
            case PERIOD_M5: return PERIOD_M1;
            default: return timeframe;
        }
    }
    
    // Check wave confirmation across timeframes
    bool CheckMultiTimeframeConfirmation() {
        int confirmations = 0;
        
        for(int tf_idx = 0; tf_idx < ArraySize(m_timeframes); tf_idx++) {
            if(ValidateWaveStructure(m_timeframes[tf_idx])) {
                confirmations++;
            }
        }
        
        m_waveConfirmationCount = confirmations;
        return confirmations >= 2;  // At least 2 timeframes should confirm
    }
    
    // Validate wave structure for specific timeframe
    bool ValidateWaveStructure(ENUM_TIMEFRAMES timeframe) {
        if(m_waveCount < 5) return false;
        
        // Basic wave rules validation
        if(!ValidateBasicRules(timeframe)) return false;
        
        // Retracement validation
        if(!ValidateRetracements(timeframe)) return false;
        
        return true;
    }
    
    // Check for wave divergence
    bool CheckDivergence() {
        if(m_waveCount < 5) return false;
        
        // Get RSI values for wave points
        int rsiHandle = iRSI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE);
        if(rsiHandle == INVALID_HANDLE) return false;
        
        double rsiValues[];
        ArrayResize(rsiValues, m_waveCount);
        
        for(int idx = 0; idx < m_waveCount; idx++) {
            rsiValues[idx] = iRSIGet(rsiHandle, 0, iBarShift(Symbol(), PERIOD_CURRENT, m_waves[idx].startBar));
        }
        
        // Check for bullish divergence
        if(m_waves[m_waveCount - 1].endPrice < m_waves[m_waveCount - 3].endPrice && rsiValues[m_waveCount - 1] > rsiValues[m_waveCount - 3]) {
            m_divergence.exists = true;
            m_divergence.type = 1;
            m_divergence.startTime = m_waves[m_waveCount - 3].startBar;
            m_divergence.endTime = m_waves[m_waveCount - 1].endBar;
            return true;
        }
        
        // Check for bearish divergence
        if(m_waves[m_waveCount - 1].endPrice > m_waves[m_waveCount - 3].endPrice && rsiValues[m_waveCount - 1] < rsiValues[m_waveCount - 3]) {
            m_divergence.exists = true;
            m_divergence.type = -1;
            m_divergence.startTime = m_waves[m_waveCount - 3].startBar;
            m_divergence.endTime = m_waves[m_waveCount - 1].endBar;
            return true;
        }
        
        m_divergence.exists = false;
        return false;
    }
    
    // Validate basic wave rules for specific timeframe
    bool ValidateBasicRules(ENUM_TIMEFRAMES timeframe) {
        // Rule 1: Wave 2 cannot retrace more than 100% of Wave 1
        if(m_waves[1].endPrice < m_waves[0].endPrice) return false;
        
        // Rule 2: Wave 3 cannot be the shortest
        double wave1Length = MathAbs(m_waves[1].endPrice - m_waves[0].endPrice);
        double wave3Length = MathAbs(m_waves[3].endPrice - m_waves[2].endPrice);
        double wave5Length = MathAbs(m_waves[5].endPrice - m_waves[4].endPrice);
        
        if(wave3Length < wave1Length && wave3Length < wave5Length) return false;
        
        // Rule 3: Wave 4 cannot enter Wave 1's price territory
        if(m_waves[3].endPrice > m_waves[0].endPrice) return false;
        
        return true;
    }
    
    // Validate wave retracements for specific timeframe
    bool ValidateRetracements(ENUM_TIMEFRAMES timeframe) {
        // Wave 2 retracement (23.6% - 61.8%)
        double wave1Length = MathAbs(m_waves[1].endPrice - m_waves[0].endPrice);
        double wave2Retracement = MathAbs(m_waves[2].endPrice - m_waves[1].endPrice) / wave1Length;
        
        if(wave2Retracement < m_retracementLevel || wave2Retracement > 1.0)
            return false;
            
        // Wave 4 retracement (23.6% - 38.2%)
        double wave3Length = MathAbs(m_waves[3].endPrice - m_waves[2].endPrice);
        double wave4Retracement = MathAbs(m_waves[4].endPrice - m_waves[3].endPrice) / wave3Length;
        
        if(wave4Retracement < m_retracementLevel || wave4Retracement > 0.382)
            return false;
            
        return true;
    }
    
    // Get wave accuracy
    double GetWaveAccuracy() {
        return m_waveAccuracy;
    }
    
    // Update wave accuracy
    void UpdateWaveAccuracy(bool predictionCorrect) {
        m_waveAccuracy = (m_waveAccuracy * 0.9) + (predictionCorrect ? 0.1 : 0);
    }
    
    // Get wave confirmation count
    int GetWaveConfirmationCount() {
        return m_waveConfirmationCount;
    }
    
    // Get divergence information
    bool GetDivergence(WaveDivergence &divergence) {
        divergence = m_divergence;
        return m_divergence.exists;
    }
}; 